//
//  DictProtocolDictionary.m
//  Lookup
//
//  Created by Mathieu on 17/07/06.
//  Copyright 2006 __MyCompanyName__. All rights reserved.
//

#import "DictProtocolDictionary.h"

@implementation DictProtocolDictionary


#pragma mark Initialisers
- (id) init {
	self = [super init];
	if (self != nil) {
		ldconn = nil; //the struct that contains all the neatorama connection information. 
	}
	return self;
}

-(NSString *)dictType{
	return @"DictProtocolDict";
}

-(bool)isRemote{
	return YES;
}

#pragma mark Archiving Support
- (void)encodeWithCoder:(NSCoder *)coder
{
    [super encodeWithCoder:coder];
		[coder encodeObject:[self valueForKey:@"client"] forKey:@"DPDClient"];
        [coder encodeObject:[self valueForKey:@"databaseName"] forKey:@"DPDDatabaseName"];
		[coder encodeObject:[self valueForKey:@"username"] forKey:@"DPDUsername"];
		[coder encodeObject:[self valueForKey:@"password"] forKey:@"DPDPassword"];
		[coder encodeObject:[self valueForKey:@"serverName"] forKey:@"DPDServerName"];
		[coder encodeObject:[self valueForKey:@"timeout"] forKey:@"DPDTimeout"];
    return;
}


//this is simply a method that is being run when something is being unarchived. it IS an instance method though... but of what?? A Dict Protocol Dict.
- (id)initWithCoder:(NSCoder *)coder
{
	//determine whether this dictionary already exists in this moc
	//set up the fetch request
	NSError *fetchError = nil; 
	NSEntityDescription *dictEntityDescription = [NSEntityDescription entityForName:@"Dictionary" inManagedObjectContext:[[NSApp delegate] managedObjectContext]]; 
	NSFetchRequest *dictRequest = [[[NSFetchRequest alloc] init] autorelease]; 
	[dictRequest setEntity:dictEntityDescription]; 
	
	NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name LIKE[c] %@", [coder decodeObjectForKey:@"DName"]];
	[dictRequest setPredicate:predicate];
	//perform the request
	NSArray *existingDicts = [[[NSApp delegate] managedObjectContext] executeFetchRequest:dictRequest error:&fetchError]; 
	
	//if there's not a dictionary of the same name already
	if([existingDicts count] == 0){
		DictProtocolDictionary *dict = [NSEntityDescription insertNewObjectForEntityForName:@"DictProtocolDict" 
																	 inManagedObjectContext:[[NSApp delegate] managedObjectContext]];
		//selfdict = [super initWithCoder:coder];
			// Can decode keys in any order
		[dict setValue:[coder decodeObjectForKey:@"DPDClient"] forKey:@"client"];
		[dict setValue:[coder decodeObjectForKey:@"DPDDatabaseName"] forKey:@"databaseName"];
		[dict setValue:[coder decodeObjectForKey:@"DPDUsername"] forKey:@"username"];
		[dict setValue:[coder decodeObjectForKey:@"DPDPassword"] forKey:@"password"];
		[dict setValue:[coder decodeObjectForKey:@"DPDServerName"] forKey:@"serverName"];
		[dict setValue:[coder decodeObjectForKey:@"DPDTimeout"] forKey:@"timeout"];
		[dict setValue:[coder decodeObjectForKey:@"DEncoding"] forKey:@"encoding"];
		//Generic dictionary attributes
		[dict setValue:[coder decodeObjectForKey:@"DCapabilities"] forKey:@"capabilities"];
		[dict setValue:[coder decodeObjectForKey:@"DName"] forKey:@"name"];
		[dict setValue:[coder decodeObjectForKey:@"DPivotLanguage"] forKey:@"pivotLanguage"];
		[dict setValue:[coder decodeObjectForKey:@"DtargetLanguages"] forKey:@"targetLanguages"];
		[dict setValue:[coder decodeObjectForKey:@"DIsRemote"] forKey:@"isRemote"];
		[dict setValue:[coder decodeObjectForKey:@"DDictionaryIconData"] forKey:@"dictionaryIconData"];	
		[dict setValue:[coder decodeObjectForKey:@"DLocalisedName"] forKey:@"localisedName"];	

		return self;
	}
	else{
	//	NSLog(@"Already a dict by the name of %@ in the moc.", [coder decodeObjectForKey:@"DName"]);
		return nil;
	}
}

#pragma mark DictionaryMO behaviour

-(void)createConnectionMonitor{
	//check the server is available
	if(!connectionMonitor){
		connectionMonitor = [[NetworkConnectionMonitor alloc] init];
		[connectionMonitor retain];
		[connectionMonitor connectAndMonitorConnectionTo:[self valueForKey:@"serverName"]];
		//create the connection monitor with factory method
	}
}

-(bool)isAvailable{
	if([connectionMonitor isAvailable]){
		return YES;
	}
	return NO;
}
//API to connect to this dictionary. Only should be called if there is an available connection
-(void)connect{
	if([connectionMonitor isAvailable]){ //if we are able to contact, connect to the dictionary and db
		[self connectTo:[self valueForKey:@"serverName"] port:0 timeout:0 client:NULL debug:false];
		[self setDb:[self valueForKey:@"databaseName"]];
	}
	else{
		NSLog(@"The %@ dictionary was unable to connect to the server. Check your network connection and try again.", [self valueForKey:@"name"]);
	}
}

-(NetworkConnectionMonitor *)networkConnectionMonitor{
	return [[connectionMonitor retain] autorelease];
}

-(void)disconnect{
	if(!connectionMonitor){
		[connectionMonitor stopMonitoring];
		[connectionMonitor release];
		connectionMonitor = nil;
	}
	if(ldconn) 
		[self closeConnection];
	[super dealloc];
}

-(NSMutableString *)stringBlobOfDefinitions:(NSString *)word{
	NSMutableString *blob = [[NSMutableString alloc] init];
	//search for the word and pop each hit in the array
	//start the word's progress indicator
	struct ld_defanswer** defs = [self define:word]; //here's the bit that takes all the time
	//if I do call it here though, I'll have to pass the whole word though, so that the blob attribute can be set
	//because the current word will have progressed beyond here.
	//kill the word's progress indicator
	
	if(!(defs)) {
		NSLog(@"No words found."); //graceful failure.
		return nil;
	} else {
		int idx = 0;
		while(defs[idx]) {
			[blob appendString:[NSString stringWithCString:(defs[idx]->ld_answord)]];
			[blob appendString:[NSString stringWithCString:(defs[idx]->ld_ansdef)]];
			idx++;
		}
	return blob;
	}
	
}


//DEPRECIATED
// Main API to this class. Ask a dictionary object for an array of definitions for a word.
- (NSArray *)arrayOfDefinitions:(NSString *)word{
	NSManagedObjectContext *moc = [[NSApp delegate] managedObjectContext]; 
	WWManagedObject *newDef;
	NSMutableArray *definitionsArray = [[NSMutableArray alloc] init];
	//search for the word and pop each hit in the array
	struct ld_defanswer** defs = [self define:word];
//	NSLog(@"The definition is %@", defs);
	
	if(!(defs)) {
		NSLog(@"No words found."); //graceful failure.
	} else {
		int idx = 0;
		while(defs[idx]) {
			newDef = [NSEntityDescription insertNewObjectForEntityForName:@"Definition" inManagedObjectContext:moc]; //a new desctription entity
			[newDef setValue:[NSString stringWithCString:(defs[idx]->ld_answord)] forKey:@"foreign"];
			[newDef setValue:[NSString stringWithCString:(defs[idx]->ld_ansdef)] forKey:@"local"];
			[definitionsArray addObject:newDef];
			idx++;
		}
	}
	return [definitionsArray autorelease];
}


#pragma mark Framework objective C wrappers

- (int)getRespNo:(NSString *)msg{
	return ld_getrespno([msg UTF8String]);
}
- (bool)checkOk:(int)respno{
	return [self convertToBool:(ld_checkok(respno))];
}

//	connect [server] - connect to a server.
- (bool)connectTo:(NSString *)host port:(int)portNumber timeout:(int)timeout client:(NSString *)client debug:(bool)debug{
	ldconn = ld_newconn([host UTF8String], portNumber, timeout, [client UTF8String], [self convToLDBool:debug]);
	NSLog(@"Connected to host: %@ client: %@ ", host, client);
	//humanDatabaseName = [NSString stringWithString:host];
//	humanServerName = [NSString stringWithString:client];
	if(!ldconn)
		return(false);
	return(true);
	
}
//	disconnect - disconnect from a server.
- (bool)closeConnection{
	NSLog(@"Connection Closed");
	return [self convertToBool:(ld_closeconn(ldconn))];
}
//	auth [username] - authenticate.
- (bool)authenticateUser:(NSString *)user password:(NSString *)password{
	return [self convertToBool:(ld_auth(ldconn, [user UTF8String], [password UTF8String]))];

}
//	info - display server information.
- (NSString *)getServerInfo{
	return [NSString stringWithCString:ld_serverinfo(ldconn)];
}
//	listdbs - list databases available.
- (struct ld_dbs **)getDbs{
	return ld_getdbs(ldconn);
}
//	liststrats - list strategies available.
- (struct ld_dbs **)getStrats{
	return ld_getstrats(ldconn);

}
//	setdb [db] - set database to use.
- (bool)setDb:(NSString *)db{
	return [self convertToBool:(ld_setdb(ldconn, [db UTF8String]))];
}
//	setstrat [strategy] - set strategy to use.
- (bool)setStrat:(NSString *)strat{
	return [self convertToBool:ld_setstrat(ldconn, [strat UTF8String])];
} 
//	define [word] - define a word.
- (struct ld_defanswer **)define:(NSString *)aWord{
	return ld_define(ldconn, [aWord UTF8String]);
}
//	match [word] - match a word.
- (struct ld_matchanswer **)match:(NSString *)aWord{
	return ld_match(ldconn, [aWord UTF8String]);
}
//	getrep - get server response to last command.
- (NSString *)getSrvReply{
	return [NSString stringWithCString:ld_getsrvreply(ldconn)];
}
//	prerr - print error status.
- (NSString *)strError:(int)errnum{
	return [NSString stringWithCString:ld_strerror(errnum)];
}
- (int)getError{
	return ld_geterrno(ldconn);
}

- (bool)convertToBool:(ld_bool)val{
	if(val == LD_True) return YES;
	return NO;
}

- (ld_bool)convToLDBool:(bool)val{
	if(val == YES) return LD_True;
	return LD_False;
}


#pragma mark Send NA to bindings
-(NSString *)indexLocation{
	return @"NA";
}

-(NSString *)location{
	return @"NA";
}

@end
